#include "EpilForListStatementParser.h"
#include "EpilExpressionListParser.h"
#include "EpilChunkParser.h"
#include "EpilParserException.h"
#include "EpilPointerHelper.h"


EpilForListStatementParser::EpilForListStatementParser( EpilTokenStream & tokens )
: EpilSyntaxParserBase( tokens )
{
}


void EpilForListStatementParser::Parse()
{
	// forlist -> NAME {,NAME} IN explist1 DO block END
	m_statement = new EpilForListStatementCode( this->GetTokens().GetPreviousToken().location );

	// NAME
	if( this->GetTokens().GetCurrentToken().type != ETT_Identifier )
	{
		EpilPointerHelper::SafeDelete( m_statement );
		throw EpilParserException( t("Identifier expected."), this->GetTokens().GetCurrentToken().location );
	}
	m_statement->GetVariables().push_back( this->GetTokens().GetCurrentToken().text );
	this->GetTokens().MoveToNext();

	while( this->GetTokens().GetCurrentToken().type == ETT_OpComma )
	{
		// ,
		this->GetTokens().MoveToNext();

		// NAME
		if( this->GetTokens().GetCurrentToken().type != ETT_Identifier )
		{
			EpilPointerHelper::SafeDelete( m_statement );
			throw EpilParserException( t("Identifier expected."), this->GetTokens().GetCurrentToken().location );
		}
		m_statement->GetVariables().push_back( this->GetTokens().GetCurrentToken().text );
		this->GetTokens().MoveToNext();
	}

	// IN
	if( this->GetTokens().GetCurrentToken().type != ETT_KwIn )
	{
		EpilPointerHelper::SafeDelete( m_statement );
		throw EpilParserException( t("\'in\' expected."), this->GetTokens().GetCurrentToken().location );
	}
	this->GetTokens().MoveToNext();

	// explist
	EpilExpressionListParser exprListParser( this->GetTokens() );
	try
	{
		exprListParser.Parse();
	}
	catch( ... )
	{
		EpilPointerHelper::SafeDelete( m_statement );
		throw;
	}
	m_statement->SetIterators( exprListParser.GetExpressions() );

	// DO
	if( this->GetTokens().GetCurrentToken().type != ETT_KwDo )
	{
		EpilPointerHelper::SafeDelete( m_statement );
		throw EpilParserException( t("\'do\' expected."), this->GetTokens().GetCurrentToken().location );
	}
	this->GetTokens().MoveToNext();

	// block
	EpilChunkParser chunkParser( this->GetTokens() );
	try
	{
		chunkParser.Parse();
	}
	catch( ... )
	{
		EpilPointerHelper::SafeDelete( m_statement );
		throw;
	}
	m_statement->SetBlock( chunkParser.GetChunk() );

	// DO
	if( this->GetTokens().GetCurrentToken().type != ETT_KwEnd )
	{
		EpilPointerHelper::SafeDelete( m_statement );
		throw EpilParserException( t("\'end\' expected."), this->GetTokens().GetCurrentToken().location );
	}
	this->GetTokens().MoveToNext();
}